#include "BaseLoader.h"

BaseLoader::BaseLoader(const QString &user, const QString &passwd, uint bufferCapacity)
    : _sqlQuery()
    , _queryBuffer()
    , _queryBufferCapacity(bufferCapacity)
    , _numOfQueries(0)
    , _tableLastQuery("edge")
    , _queryList()
{
    _sqlQuery = QSqlQuery(QSqlDatabase::database());

    _insertHeader("edge");
}

BaseLoader::~BaseLoader()
{
    _finalizeQuery();
//    QSqlDatabase::database().close();
}

bool BaseLoader::_executeQuery()
{
    _queryList.append(pair<uint,uint>(_queryBuffer.size(), _numOfQueries));

    _queryBuffer[_queryBuffer.size()-1] = ';';

    if (!_sqlQuery.exec(_queryBuffer)) {
        cout << "Falha ao executar a query: %" << _queryBuffer.toStdString() << "%" << endl;
        return false;
    }
    _numOfQueries = 0;
    _insertHeader(_tableLastQuery);
    return true;
}

bool BaseLoader::_finalizeQuery()
{
    if (_numOfQueries > 0)
        return _executeQuery();
    return true;
}

bool BaseLoader::addEdgeElement(EdgeElement& e)
{
    // transforma o elemento em uma lista de elementos, e depois no string final de consulta
    QString tmp(serialize(e));

    if ((_queryBuffer.size() + tmp.size() > (int) _queryBufferCapacity) && (_numOfQueries > 0)) {
            if (!_executeQuery())
                return false;
    }
    _queryBuffer.append(tmp);
    _numOfQueries++;
    return true;
}

bool BaseLoader::addPathElement(const QString& path, uint id)
{
    // na primeira chamada, finaliza a inserção de edge elements
    if (_tableLastQuery != "path") {
        _tableLastQuery = "path";
        _finalizeQuery();
    }

    // serializa a consulta
    QString tmp("(");
    tmp.append(QString().setNum(id))
            .append(",\"")
            .append(path)
            .append("\"),");

    if ((_queryBuffer.size() + tmp.size() > (int) _queryBufferCapacity) && (_numOfQueries > 0)) {
            if (!_executeQuery())
                return false;
    }
    _queryBuffer.append(tmp);
    _numOfQueries++;
    return true;
}

void BaseLoader::_insertHeader(const QString& table)
{
    _queryBuffer = QString("INSERT INTO ").append(table).append(" VALUES ");
}

QString BaseLoader::serialize(EdgeElement& e) const
{
    // http://dev.mysql.com/doc/refman/5.0/en/string-syntax.html
    e.value.replace("\\","\\\\");
    e.value.replace("\'","\\\'");
    e.value.replace("\"","\\\"");

    QString line("(");
    line.append(QString().setNum(e.id).append(","));        // id
    line.append(QString().setNum(e.order).append(","));     // order
    if (e.parent_id == 0)                                   // parent_id
        line.append("NULL,");
    else
        line.append(QString().setNum(e.parent_id).append(","));
    line.append(QString().setNum(e.path_id).append(","));   // path_id
//    if (e.end_desc_id != e.id)                              // end_desc_id
        line.append(QString().setNum(e.end_desc_id).append(","));
//    else
//        line.append("NULL,");
    if (e.value.isEmpty())                                  // value
        line.append("NULL,");
    else
        line.append(QString("\"").append(e.value).append("\","));
    if (e.attribute)                                        // attribute
        line.append("1");
    else
        line.append("0");

    line.append("),");

    return line;
}

void BaseLoader::getFinalData(quint64& acBufferSize, quint64& acNumberQueries, uint& numOfDbAccess)
{
    acBufferSize = 0;
    acNumberQueries = 0;

    for (QueryList::iterator it = _queryList.begin(); it != _queryList.end(); it++) {
        acBufferSize += it->first;
        acNumberQueries += it->second;
    }
    numOfDbAccess = _queryList.size();
}

QString BaseLoader::getLastLabel(const QString& path)
{
    return path.section('/',-1);
}

void BaseLoader::loadEdgeElement(const QSqlRecord& record, EdgeElement* element)
{
    element->id = record.value("id").toInt();
    element->order = record.value("_order").toInt();
    if (record.contains("_size"))
        element->size = record.value("_size").toInt();
    element->parent_id = record.value("parent_id").toInt();
    element->path_id = record.value("path_id").toInt();
    element->end_desc_id = record.value("end_desc_id").toInt();
    element->value = record.value("value").toString();
    if (record.contains("label"))
        element->label = record.value("label").toString();
    element->attribute = record.value("attribute").toBool();
}
